package com.gzhryc.shared_device.cdcz.code.services;

import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.shared_device.cdcz.code.dao.ChargeSocketSlotDao;
import com.gzhryc.shared_device.cdcz.code.dao.db.ChargeSocket;
import com.gzhryc.shared_device.cdcz.code.dao.db.ChargeSocketSlot;
import com.gzhryc.shared_device.cdcz.code.dao.enums.ChargeSocketSlotEnum;
import com.gzhryc.shared_device.cdcz.core.enums.ECDCZPlugWorkState;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ChargeSocketSlotService {

    static Logger log = Logger.getLogger(ChargeSocketSlotService.class);

    public static ChargeSocketSlotService self() {
        return MultiDBTools.getService(ChargeSocketSlotService.class, true);
    }

    public static ChargeSocketSlotService self(String jdbcKey) {
        return MultiDBTools.getService(jdbcKey, ChargeSocketSlotService.class, true);
    }

    ChargeSocketSlotDao dao;

    public ChargeSocketSlotService(String jdbcKey) {
        dao = new ChargeSocketSlotDao(jdbcKey);
    }

    public List<ChargeSocketSlot> findByDeviceSn(String deviceSn){
        if(StringTools.isNotBlank(deviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.asc("slotNum");
            try {
                return dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public List<ChargeSocketSlot> findByDeviceSn(List<String> deviceSnList){
        if(deviceSnList != null && deviceSnList.size() > 0){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().in("deviceSn",deviceSnList);

            try {
                return dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public Long countByDeviceSn(String deviceSn){
        if(StringTools.isNotBlank(deviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            try {
                return dao.count(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public ChargeSocketSlot getByKeys(String deviceSn,Integer slotNum){
        if(StringTools.isNotBlank(deviceSn) && slotNum != null){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.and().is("slotNum",slotNum);
            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public ChargeSocketSlot getJoinByKeys(String deviceSn,Integer slotNum){
        if(StringTools.isNotBlank(deviceSn) && slotNum != null){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.and().is("slotNum",slotNum);
            try {
                return dao.getJoin(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    /**
     * 获取空闲的卡槽
     * @param deviceSn
     * @return
     */
    public List<ChargeSocketSlot> findFreeByDeviceSn(String deviceSn){
        if(StringTools.isNotBlank(deviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.and().is("state", ChargeSocketSlotEnum.State.Free.index());
            conditions.asc("slotNum");
            try {
                return dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public List<ChargeSocketSlot> findWorkingByDeviceSn(String deviceSn){
        if(StringTools.isNotBlank(deviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.and().is("state",ChargeSocketSlotEnum.State.Working.index());
            try {
                return dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public List<ChargeSocketSlot> findWorkingByDeviceSn(List<String> deviceSnList){
        if(deviceSnList != null && deviceSnList.size() > 0){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().in("deviceSn",deviceSnList);
            conditions.and().is("state",ChargeSocketSlotEnum.State.Working.index());
            try {
                return dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public Long countWorkingByDeviceSn(String deviceSn){
        if(StringTools.isNotBlank(deviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.and().is("state",ChargeSocketSlotEnum.State.Working.index());
            try {
                return dao.count(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return 0L;
    }

    public boolean addEmptySlot(String deviceSn,Integer slotTotal){
        if(StringTools.isNotBlank(deviceSn) && slotTotal != null && slotTotal > 0){
            List<ChargeSocketSlot> socketSlotList = new ArrayList<>();
            for(int i=1;i<=slotTotal;i++){
                ChargeSocketSlot slot = new ChargeSocketSlot();
                slot.setDeviceSn(deviceSn);
                slot.setSlotNum(i);
                slot.setState(ChargeSocketSlotEnum.State.Free.index());
                slot.setCreateDate(new Date());
                socketSlotList.add(slot);
            }
            try {
                return dao.insert(socketSlotList) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean add(List<ChargeSocketSlot> socketSlotList){
        if(socketSlotList != null && socketSlotList.size() > 0) {
            try {
                return dao.insert(socketSlotList) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean checkSlotTotal(ChargeSocket chargeSocket){
        Long total = this.countByDeviceSn(chargeSocket.getDeviceSn());
        if(total == null || total == 0){
           return this.addEmptySlot(chargeSocket.getDeviceSn(),chargeSocket.getSlotTotal());
        }else if(total.intValue() < chargeSocket.getSlotTotal()){
            List<ChargeSocketSlot> socketSlotList = this.findByDeviceSn(chargeSocket.getDeviceSn());
            for(int i=1;i<=chargeSocket.getSlotTotal();i++){
                boolean flag = false;
                int j = 0;
                for(;j < socketSlotList.size();j++){
                    ChargeSocketSlot socketSlot = socketSlotList.get(j);
                    if(socketSlot.getSlotNum().equals(i)){
                        flag = true;
                        break;
                    }
                }

                if(flag){
                    socketSlotList.remove(j);
                }else{
                    ChargeSocketSlot socketSlot = new ChargeSocketSlot();
                    socketSlot.setDeviceSn(chargeSocket.getDeviceSn());
                    socketSlot.setSlotNum(i);
                    socketSlot.setState(ChargeSocketSlotEnum.State.Free.index());
                    socketSlot.setCreateDate(new Date());
                    try {
                        dao.insert(socketSlot);
                    } catch (SQLException e) {
                        log.error(e.getMessage(),e);
                    }
                }
            }

            if(socketSlotList.size() > 0){
                for(ChargeSocketSlot socketSlot : socketSlotList){
                   this.deleteByKeys(socketSlot.getDeviceSn(),socketSlot.getSlotNum());
                   log.info("卡槽数量检查，删除设备：{{0}}，卡槽：{{1}}",socketSlot.getDeviceSn(),socketSlot.getSlotNum());
                }
            }
            return true;
        }else if(total.intValue() > chargeSocket.getSlotTotal()){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",chargeSocket.getDeviceSn());
            conditions.and().gt("slotNum",chargeSocket.getSlotTotal());

            try {
                return dao.deleteByCondition(conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }else{
            return true;
        }
        return false;
    }

    public boolean updateInfo(ChargeSocketSlot socketSlot ,Integer state,Integer overloadState,Integer powerState,Integer temperatureState) {
        if (socketSlot != null && StringTools.isNotBlank(socketSlot.getDeviceSn()) && socketSlot.getSlotNum() != null) {
            boolean flag = false;
            ChargeSocketSlot updateEntity = new ChargeSocketSlot();
            if(socketSlot.getOverloadState() == null || !socketSlot.getOverloadState().equals(overloadState)){
                flag = true;
                updateEntity.setOverloadState(overloadState);
            }

            if(socketSlot.getPowerState() == null || !socketSlot.getPowerState().equals(powerState)){
                flag = true;
                updateEntity.setPowerState(powerState);
            }

            if(socketSlot.getTemperatureState() == null || !socketSlot.getTemperatureState().equals(temperatureState)){
                flag = true;
                updateEntity.setTemperatureState(temperatureState);
            }

            if(ChargeSocketSlotEnum.State.Working.index().equals(socketSlot.getState())){
                if(!ECDCZPlugWorkState.Charge.index().equals(state)) {
                    log.info("系统卡槽工作中，但上报信息非工作中，上报状态：{{0}}",ECDCZPlugWorkState.note(state));
                    updateEntity.setState(ChargeSocketSlotEnum.State.Free.index());
                    flag = true;
                }
            }else {
                if(ECDCZPlugWorkState.Charge.index().equals(state)) {
                    updateEntity.setState(ChargeSocketSlotEnum.State.Working.index());
                    flag = true;
                }
            }

            if(flag) {
                Conditions conditions = new Conditions(ChargeSocketSlot.class);
                conditions.and().is("deviceSn", socketSlot.getDeviceSn());
                conditions.and().is("slotNum", socketSlot.getSlotNum());

                try {
                    if(dao.updateNotNull(updateEntity, conditions) <= 0){
                        log.error("修改卡槽信息失败");
                    }
                } catch (SQLException e) {
                    log.error(e.getMessage(), e);
                }
                return true;
            }
        }
        return false;
    }

    public boolean toWorking(String deviceSn,Integer slotNum,String tradeNo){
        if (StringTools.isNotBlank(deviceSn) && slotNum != null) {
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn", deviceSn);
            conditions.and().is("slotNum", slotNum);

            ChargeSocketSlot socketSlot = new ChargeSocketSlot();
            socketSlot.setState(ChargeSocketSlotEnum.State.Working.index());
            socketSlot.setCurrentTradeNo(tradeNo);

            try {
                return dao.updateNotNull(socketSlot, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean freeToWorking(String deviceSn,Integer slotNum,String tradeNo){
        if (StringTools.isNotBlank(deviceSn) && slotNum != null) {
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn", deviceSn);
            conditions.and().is("slotNum", slotNum);
            conditions.and().is("state",ChargeSocketSlotEnum.State.Free.index());

            ChargeSocketSlot socketSlot = new ChargeSocketSlot();
            socketSlot.setState(ChargeSocketSlotEnum.State.Working.index());
            socketSlot.setCurrentTradeNo(tradeNo);

            try {
                return dao.updateNotNull(socketSlot, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean toFree(String deviceSn,Integer slotNum){
        if (StringTools.isNotBlank(deviceSn) && slotNum != null) {
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn", deviceSn);
            conditions.and().is("slotNum", slotNum);

            ChargeSocketSlot socketSlot = new ChargeSocketSlot();
            socketSlot.setState(ChargeSocketSlotEnum.State.Free.index());

            try {
                return dao.updateNotNull(socketSlot, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean toFree(String deviceSn){
        if (StringTools.isNotBlank(deviceSn)) {
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn", deviceSn);

            ChargeSocketSlot socketSlot = new ChargeSocketSlot();
            socketSlot.setState(ChargeSocketSlotEnum.State.Free.index());

            try {
                return dao.updateNotNull(socketSlot, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean deleteByKeys(String deviceSn,Integer slotNum){
        if(StringTools.isNotBlank(deviceSn) && slotNum != null){
            Conditions conditions = new Conditions(ChargeSocketSlot.class);
            conditions.and().is("deviceSn",deviceSn);
            conditions.and().is("slotNum",slotNum);

            try {
                return dao.deleteByCondition(conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean deleteByDeviceSn(String deviceSn) throws LogicException {
        if(StringTools.isNotBlank(deviceSn)) {
            Conditions condition = new Conditions(ChargeSocketSlot.class);
            condition.and().is("deviceSn", deviceSn);
            try {
                return dao.deleteByCondition(condition) >= 0;
            } catch (SQLException e) {
               log.error(e.getMessage(),e);
            }
        }
        return false;
    }
}
